package org.jeecg.modules.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.jeecg.modules.hand.LoginHandler;
import org.jeecg.modules.hand.NettyClientHandler;
import org.jeecg.modules.hand.NettyServerHandler;
import org.jeecg.modules.utils.CustomMessageDecoder;
import org.jeecg.modules.utils.MessageEncoder;

public class NettyServer {
    /**
     * 创建服务端，并绑定端口
     */
    public static void bind(String port) throws InterruptedException {
        //创建boss线程用于处理链接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //创建work线程用于处理链接上的io操作，含有子线程NioEventGroup个数为CPU核数大小的2倍
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //创建ServerBootstrap对象，用于启动服务端
            ServerBootstrap bootstrap = new ServerBootstrap();
            //将boss线程和work线程暂存到bootstrap中
            bootstrap.group(bossGroup, workerGroup);
            //设置服务端通道类型NioServerSocketChannel
            bootstrap.channel(NioServerSocketChannel.class);
            //设置子处理器，用于处理workerGroup线程中的事件,使用socket类型的通道
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                //初始化通道方法
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //根据通道获取管道，并添加处理器
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    //先解码，
                    pipeline.addLast(new CustomMessageDecoder());
                    //在登录
                    pipeline.addLast(new LoginHandler());
                    pipeline.addLast(new NettyClientHandler());
                    pipeline.addLast(new MessageEncoder());



                }
            });
            //设置启动参数，初始化服务器链接队列大小，服务端处理客户端请求时顺序处理，一个时间只能处理一个客户端请求，当有多个请求同时到达时，未处理的请求先放入队列中
            bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            //绑定端口并启动服务器，bind方法是异步的，sync方法是同步阻塞的，等待绑定完成,返回一个ChannelFuture对象
            ChannelFuture future = bootstrap.bind(Integer.parseInt(port)).sync();
            System.out.println("Server started and listening on " + port);
            // 等待服务器 socket 关闭 。在这个例子中，这不会发生，因为 shutdownHint() 没有被调用。
            future.channel().closeFuture().sync();
        } finally {
            //关闭boos线程
            bossGroup.shutdownGracefully();
            //关闭工作现场
            workerGroup.shutdownGracefully();
        }
    }
}
